![]() |
|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
|
![]() |
![]() |
Tips 'N Tricks
SummaryBy Tony Colston
Creating splash screens in Java by using AWT and Swing is well documented in the current literature. However, the existing solutions are not fully featured in that documentation and do not explain all the intricacies of threading in Swing. This tip presents a splash-screen component on which the user can click to make it disappear. In addition, the component will also have a timer controlling the splash screen so that it will automatically disappear after a set period of time. (1,000 words)
lmost
all modern applications have a splash screen. Using a splash screen is a way to
advertise your product. It is also used to indicate to the user that something
is happening in your application during long startup times. Current literature
explains how to create a splash screen but does not show how to integrate one
into your application (see books by David
Geary). Users can quickly remove some splash screens by simply clicking
anywhere on them. Some splash screens stay visible only until the application is
loaded. Other splash screens are visible even after the user has started the
application.
Wouldn't you like to be able to do all those things in Java? By using Swing with threads, you can!
Here is a first swing (no pun intended) at a class for a splash screen created for use in an application:
class SplashWindow1 extends
JWindow
{
public SplashWindow1(String filename,
Frame
f)
{
super(f);
JLabel
l = new JLabel(new
ImageIcon(filename));
getContentPane().add(l,
BorderLayout.CENTER);
pack();
Dimension
screenSize
=
Toolkit.getDefaultToolkit().getScreenSize();
Dimension
labelSize =
l.getPreferredSize();
setLocation(screenSize.width/2
-
(labelSize.width/2),
screenSize.height/2
-
(labelSize.height/2));
setVisible(true);
screenSize
= null;
labelSize =
null;
}
}
The SplashWindow1
class extends Swing's JWindow
.
JWindow
is a heavyweight container. It also has none of the normal
items that appear in other windows, such as a title bar, window management
buttons, or even a visible frame edge. Therefore, JWindow
is
perfect for a splash screen. The code above assumes an image file is located in
the current directory. Once the image is loaded by way of the
ImageIcon
, the image is placed in the center of the
JWindow
. The JWindow
is packed to let Swing resize the
window correctly, and then it is moved to the center of the screen and set
visible. You can find a similar version of that code in the reference material
in Resources.
If you were to actually run the above code, you would unfortunately have a nicely centered splash screen that will not close! To make it close, you must add code:
class SplashWindow2 extends
JWindow
{
public SplashWindow2(String filename,
Frame
f)
{
super(f);
JLabel
l = new JLabel(new
ImageIcon(filename));
getContentPane().add(l,
BorderLayout.CENTER);
pack();
Dimension
screenSize
=
Toolkit.getDefaultToolkit().getScreenSize();
Dimension
labelSize =
l.getPreferredSize();
setLocation(screenSize.width/2
-
(labelSize.width/2),
screenSize.height/2
-
(labelSize.height/2));
addMouseListener(new
MouseAdapter()
{
public
void mousePressed(MouseEvent
e)
{
setVisible(false);
dispose();
}
});
setVisible(true);
}
}
The only difference in that version of the SplashWindow
class is
that there is now an anonymous MouseListener
installed on the
JWindow
. That will allow the user to click on the splash screen to
make it disappear.
At that point, you will have a nice splash screen that can be removed but will not disappear on its own. You will then have to add code to remove the splash screen after a certain amount of time. Then you should be thinking threads. And if you've worked with Swing at all, you know that making threaded calls can be tricky at best. For reasons why and a more in-depth explanation of threads and Swing, see Resources.
class SplashWindow3 extends
JWindow
{
public SplashWindow3(String filename,
Frame f, int
waitTime)
{
super(f);
JLabel
l = new JLabel(new
ImageIcon(filename));
getContentPane().add(l,
BorderLayout.CENTER);
pack();
Dimension
screenSize
=
Toolkit.getDefaultToolkit().getScreenSize();
Dimension
labelSize =
l.getPreferredSize();
setLocation(screenSize.width/2
-
(labelSize.width/2),
screenSize.height/2
-
(labelSize.height/2));
addMouseListener(new
MouseAdapter()
{
public
void mousePressed(MouseEvent
e)
{
setVisible(false);
dispose();
}
});
final
int pause = waitTime;
final
Runnable closerRunner = new
Runnable()
{
public
void
run()
{
setVisible(false);
dispose();
}
};
Runnable
waitRunner = new
Runnable()
{
public
void
run()
{
try
{
Thread.sleep(pause);
SwingUtilities.invokeAndWait(closerRunner);
}
catch(Exception
e)
{
e.printStackTrace();
//
can catch
InvocationTargetException
//
can catch
InterruptedException
}
}
};
setVisible(true);
Thread
splashThread = new Thread(waitRunner,
"SplashThread");
splashThread.start();
}
}
The general idea here is to first create a Thread
object that
will pause for a specific amount of time. In the above code, the thread will
pause for four seconds. When that thread wakes up, it will close the splash
screen. Since Swing is not thread-safe, you should not affect the state of any
UI component unless the code is being executed on the event-dispatching thread.
The event-dispatching thread is the thread that handles drawing and event
handling in Swing.
To get around that limitation, Swing designers gave the programmer the
ability to add runnable objects to the UI event queue in a safe manner. In this
case, you are going to use the runnable object's closeRunner
to do
the dirty work. You pass the runnable object to the static method
SwingUtilities.invokeAndWait()
. Then
SwingUtilities.invokeAndWait()
will execute all pending UI activity
and execute the run method on the runnable object closeRunner
,
which is passed to the method. By using a separate thread to handle the splash
screen's closing, the application that is displayed behind the splash screen is
visible and responsive during the entire operation.
If you want a splash screen that is always visible and that the user cannot
remove, you must remove the code that hides the splash screen. If you want a
splash screen that the user must close manually, you can call the
setVisible(false)
and dispose()
methods on the
SplashWindow3
object just like any other JWindow
.
Conclusion
By using the
SwingUtilities.invokeAndWait()
method, you can safely create a
multithreaded Swing splash screen. A user can click on the splash screen to
remove it, or the splash screen will disappear on its own after a set amount of
time. The threading model that Swing supports will allow the application to
remain responsive and usable behind the splash screen.
About the author
Tony Colston has been programming professionally since 1991,
beginning with the development of ATMs and debit cards. He now works for
Tennessee-based Buckman Labs, where he spends his days dreaming up new ways to
distribute reports in realtime over the Web. His hobbies include playing
basketball (badly), Quake III, and Diablo II. When he is not being a nerd, he
spends his time worshiping his wife Beth who strangely thinks nerds are cool.
You can check out his Webpage at http://members.xoom.com/Tonetheman.
![]() |
![]() |
|
![]() |
Copyright © 2001 JavaWorld.com, an IDG Communications company |
![]() |
![]() |
![]() |